﻿using System;
using System.IO;
using System.Net.Sockets;
using System.Net;

namespace Innovative.ProXr
{
	public class NetworkDeviceConfiguration : DisposableBase, IRelayDeviceConfiguration
	{
		private int _port = 2101;
		private IPAddress _ipAddress = null;
		private TimeSpan _commandTimeout = TimeSpan.FromMilliseconds(1000);
		private TcpClient _client = null;

		/// <summary>
		/// Creates and instance of the NetworkDeviceConfiguration with the specified IP Address and port.
		/// </summary>
		public NetworkDeviceConfiguration(string ipAddress = "127.0.0.1", int port = 2101)
		{
			this.IpAddress = IPAddress.Parse(ipAddress);
		}

		/// <summary>
		/// Creates and instance of the NetworkDeviceConfiguration with the specified IP Address and port.
		/// </summary>
		public NetworkDeviceConfiguration(IPAddress ipAddress, int port = 2101)
		{
			this.IpAddress = ipAddress;
		}

		/// <summary>
		/// Get/sets the TCP/IP port of the relay controller.
		/// </summary>
		public int Port
		{
			get
			{
				return _port;
			}
			set
			{
				_port = value;
			}
		}

		/// <summary>
		/// Get/sets the IP Address of the relay controller.
		/// </summary>
		public IPAddress IpAddress
		{
			get
			{
				return _ipAddress;
			}
			set
			{
				_ipAddress = value;
			}
		}

		/// <summary>
		/// Gets and EndPoint that can be used to connect to the relay controller.
		/// </summary>
		public IPEndPoint EndPoint
		{
			get
			{
				return new IPEndPoint(this.IpAddress, this.Port);
			}
		}

		#region IRelayDeviceConfiguration
		/// <summary>
		/// Get/sets a TimeSpan to indicate how long to wait for a response from
		/// the relay controller until a timeout exception is thrown.
		/// </summary>
		public TimeSpan CommandTimeout
		{
			get
			{
				return _commandTimeout;
			}
			set
			{
				_commandTimeout = value;
			}
		}

		/// <summary>
		/// Connects to the relay controller specified in this configuration. 
		/// </summary>
		/// <returns>Returns True if successful, False otherwise.</returns>
		public bool Connect()
		{
			bool returnValue = false;

			// ***
			// *** Disconnect if connected
			// ***

			if (_client == null)
			{
				_client = new TcpClient();
				_client.ReceiveTimeout = (int)this.CommandTimeout.TotalSeconds;
				_client.SendTimeout = (int)this.CommandTimeout.TotalSeconds;
				_client.Connect(this.IpAddress, this.Port);
				returnValue = _client.Connected;
			}

			return returnValue;
		}

		/// <summary>
		/// Disconnects a connected device.
		/// </summary>
		/// <returns>True if successful, False otherwise (False if not connected).</returns>
		public bool Disconnect()
		{
			bool returnValue = false;

			if (_client != null)
			{
				_client.Close();
				((IDisposable)_client).Dispose();
				_client = null;
				returnValue = true;
			}

			return returnValue;
		}

		/// <summary>
		/// Gets a stream object to allow two communication with the device.
		/// </summary>
		/// <returns>Returns a Stream object for communicating with the device.</returns>
		public Stream GetStream()
		{
			Stream returnValue = Stream.Null;

			if (_client != null && _client.Connected)
			{
				returnValue = _client.GetStream();
			}
			else
			{
				throw new DeviceNotConnectedException();
			}

			return returnValue;
		}
		#endregion

		protected override void OnDisposeManagedObjects()
		{
			this.Disconnect();
			base.OnDisposeManagedObjects();
		}
	}
}
